# -*- coding: utf-8 -*-
import time
from datetime import datetime
from decimal import Decimal

from sqlalchemy import func

from common.bankcard.model import BANK_CARD_TYPE, BankcardData
from common.recharge.model import *
from common.risk.model import RiskyUser, RiskyIP, ACTION_TYPE, RISK_STATUS
from common.utils import exceptions as err
from common.utils import track_logging
from common.utils.db import list_object, upsert, delete
from common.utils.db import paginate
from common.utils.decorator import sql_wrapper
from common.utils.tz import date_seconds_ago, to_ts

_LOGGER = track_logging.getLogger(__name__)


@sql_wrapper
def create_order(mch_id, out_trade_no, user_id, amount, context, receive_card_num, notify_url, region, star,
                 sdk_version, receive_card_name):
    '''  V1 charge创建订单 '''
    try:
        recharge_order = RechargeOrder()
        recharge_order.mch_id = int(mch_id)
        recharge_order.user_id = user_id
        recharge_order.context = context
        recharge_order.receive_card_num = receive_card_num
        recharge_order.receive_card_name = receive_card_name
        recharge_order.amount = amount
        recharge_order.out_trade_no = out_trade_no
        recharge_order.notify_url = notify_url
        recharge_order.status = RECHARGE_ORDER_STATUS.CREATED
        recharge_order.region = region
        recharge_order.star = star
        recharge_order.sdk_version = sdk_version
        recharge_order.created_at = datetime.utcnow()
        recharge_order.save()
        return recharge_order
    except Exception as e:
        _LOGGER.exception('create bank order error, %s', e)
        raise err.DataError()


@sql_wrapper
def create_recharge_order(order_data):
    """ V2 recharge创建订单 """
    user = RiskyUser.query.filter(
        RiskyUser.mch_id == order_data['mch_id']).filter(
        RiskyUser.user_id == order_data['user_id']).first()
    if user and user.recharge_status == RISK_STATUS.DISABLED:
        raise err.ParamError(u'用户禁止上分操作')
    try:
        recharge_order = RechargeOrder()
        for k, v in order_data.iteritems():
            setattr(recharge_order, k, v)
        recharge_order.created_at = datetime.utcnow()
        recharge_order.status = RECHARGE_ORDER_STATUS.WAIT
        recharge_order.save(auto_commit=False)

        # 更新玩家风控数据
        if not user:
            user = RiskyUser()
            for param in ['mch_id', 'user_id', 'star', 'client_ip', 'region', 'register_day']:
                setattr(user, param, order_data.get(param))
            for param in ['recharge_avg', 'recharge_total', \
                          'recharge_req_count', 'recharge_succ_count', 'recharge_fail_count', \
                          'recharge_succ_rate', 'withdraw_total', 'withdraw_succ_count', \
                          'withdraw_fail_count', 'withdraw_req_count']:
                setattr(user, param, 0)
            user.recharge_status = 1
        user.recharge_req_count += 1
        user.register_day = order_data.get('register_day', 0)
        user.star = order_data.get('star')
        user.save(auto_commit=False)

        user_ip = RiskyIP()
        user_ip.risk_user_id = user.id
        user_ip.action_type = ACTION_TYPE.RECHARGE
        user_ip.ip = order_data.get('client_ip')
        user_ip.region = recharge_order.region
        user_ip.created_at = datetime.utcnow()
        user_ip.save(auto_commit=False)

        orm.session.commit()
        return recharge_order
    except Exception as e:
        _LOGGER.exception('create recharge order error, %s', e)
        orm.session.rollback()
        raise err.DataError()
    finally:
        orm.session.close()


def trans_order_status(order_status):
    ''' 将unionagency 订单状态转换未商户可以理解的'''
    if order_status == RECHARGE_ORDER_STATUS.DONE:
        return RECHARGE_ORDER_SUMMARY.DONE
    elif order_status == RECHARGE_ORDER_STATUS.REJECTED:
        return RECHARGE_ORDER_SUMMARY.REJECTED
    else:
        return RECHARGE_ORDER_SUMMARY.CREATED


def get_time_remain(order):
    if order.status not in [RECHARGE_ORDER_STATUS.DONE, RECHARGE_ORDER_STATUS.REJECTED]:
        time_remain = EXPIRE_TIME - (int(time.time()) - to_ts(order.created_at))
        if time_remain < 0:
            return 0
        return time_remain
    else:
        return 0


@sql_wrapper
def get_order(order_id):
    return RechargeOrder.query.filter(RechargeOrder.id == order_id).first()


@sql_wrapper
def get_unfilled_order(order_id):
    return RechargeOrder.query.filter(
        RechargeOrder.id == order_id).filter(
        RechargeOrder.status == RECHARGE_ORDER_STATUS.CREATED).first()


@sql_wrapper
def get_order_by_out_trade_no(mch_id, out_trade_no):
    return RechargeOrder.query.filter(
        RechargeOrder.mch_id == mch_id).filter(
        RechargeOrder.out_trade_no == out_trade_no).first()


@sql_wrapper
def get_order_by_third_id(third_id):
    return RechargeOrder.query.filter(RechargeOrder.third_id == third_id).first()


@sql_wrapper
def upsert_order(info, id=None):
    return upsert(RechargeOrder, info, id)


@sql_wrapper
def list_order(query_dct):
    query, total_count = list_object(query_dct, RechargeOrder, disable_paginate=True)
    total_amount = query.statement.with_only_columns([func.sum(RechargeOrder.amount)])
    total_amount = query.session.execute(total_amount).scalar()
    query = paginate(query, query_dct)
    return query.all(), total_count, total_amount


@sql_wrapper
def delete_order(id):
    delete(RechargeOrder, id)


@sql_wrapper
def add_order_success(order_id, reason=None):
    try:
        order = RechargeOrder.query.filter(
            RechargeOrder.id == order_id).filter(
            RechargeOrder.status.in_(
                [RECHARGE_ORDER_STATUS.WAIT, RECHARGE_ORDER_STATUS.THIRD, RECHARGE_ORDER_STATUS.OVERTIME])).first()
        if order:
            order.status = RECHARGE_ORDER_STATUS.DONE
            order.payed_at = datetime.utcnow()
            order.detail = reason
            order.save(auto_commit=False)

            # 更新玩家风控数据
            user = RiskyUser.query.filter(
                RiskyUser.mch_id == order.mch_id).filter(
                RiskyUser.user_id == order.user_id).first()
            if user:
                user.recharge_total += order.amount
                user.recharge_succ_count += 1
                user.recharge_succ_rate += int(float(user.recharge_succ_count) / (user.recharge_req_count or 1) * 100)
                user.recharge_avg = float(user.recharge_total) / (user.recharge_succ_count or 1)
                user.save(auto_commit=False)

            # 更新卡统计数据
            card_data = BankcardData.query.filter(
                BankcardData.name == order.receive_card_name).first()
            if card_data:
                card_data.recharge_count += 1
                card_data.daily_recharge_count += 1
                card_data.recharge_total += Decimal(float(order.amount))
                card_data.daily_recharge_total += Decimal(float(order.amount))
                card_data.save(auto_commit=False)
            orm.session.commit()
            return order
        else:
            _LOGGER.warn('add_recharge_order_success, cocurrency occured! recharge_order_id[%s]', order_id)
            return False
    except Exception as e:
        _LOGGER.error('add_order_success fail %s: %s' % (order_id, e))
        orm.session.rollback()
        raise err.DataError()
    finally:
        orm.session.close()


@sql_wrapper
def add_order_fail(order_id, reason):
    try:
        order = RechargeOrder.query.filter(
            RechargeOrder.id == order_id).filter(
            RechargeOrder.status.in_(
                [RECHARGE_ORDER_STATUS.WAIT, RECHARGE_ORDER_STATUS.THIRD, RECHARGE_ORDER_STATUS.OVERTIME])).first()
        if order:
            order.status = RECHARGE_ORDER_STATUS.REJECTED
            order.detail = reason
            order.save(auto_commit=False)

            user = RiskyUser.query.filter(
                RiskyUser.mch_id == order.mch_id).filter(
                RiskyUser.user_id == order.user_id).first()
            if user:
                user.recharge_fail_count += 1
                user.save(auto_commit=False)
            orm.session.commit()
            return order
        else:
            _LOGGER.warn('add_recharge_order_fail, cocurrency occured! recharge_order_id[%s]', order_id)
            return False
    except Exception as e:
        _LOGGER.error('add_order_fail fail %s: %s' % (order_id, e))
        orm.session.rollback()
        raise err.DataError()
    finally:
        orm.session.close()


@sql_wrapper
def add_notify_success(order_id):
    recharge_order = RechargeOrder.query.filter(
        RechargeOrder.id == order_id).with_lockmode('update').first()
    recharge_order.notify_status = RECHARGE_NOTIFY_STATUS.SUCC
    if recharge_order.notify_count:
        recharge_order.notify_count += 1
    else:
        recharge_order.notify_count = 1
    recharge_order.notify_at = datetime.utcnow()
    recharge_order.save()
    return recharge_order


@sql_wrapper
def add_notify_fail(order_id):
    _LOGGER.info("will update order notify fail %s" % order_id)
    recharge_order = RechargeOrder.query.filter(
        RechargeOrder.id == order_id).with_lockmode('update').first()
    if recharge_order.notify_status == RECHARGE_NOTIFY_STATUS.SUCC:
        return
    recharge_order.notify_status = RECHARGE_NOTIFY_STATUS.FAIL
    if recharge_order.notify_count:
        recharge_order.notify_count += 1
    else:
        recharge_order.notify_count = 1
    recharge_order.notify_at = datetime.utcnow()
    recharge_order.save()
    _LOGGER.info("update order notify fail %s" % order_id)

    return recharge_order


@sql_wrapper
def expire_timeout_order():
    order_ids = []
    third_ids = []
    expired_date = date_seconds_ago(EXPIRE_TIME)
    orders = RechargeOrder.query.filter(
        RechargeOrder.status.in_([RECHARGE_ORDER_STATUS.THIRD, RECHARGE_ORDER_STATUS.WAIT])).filter(
        RechargeOrder.created_at <= expired_date).all()
    RechargeOrder.query.filter(
        RechargeOrder.status.in_([RECHARGE_ORDER_STATUS.THIRD, RECHARGE_ORDER_STATUS.WAIT])).filter(
        RechargeOrder.created_at <= expired_date).update({
        'status': RECHARGE_ORDER_STATUS.OVERTIME,
        'detail': 'auto expired',
        'updated_at': datetime.utcnow()
    }, synchronize_session='fetch')
    orm.session.commit()
    for order in orders:
        order_ids.append(order.id)
        if order.receive_card_type is None or order.receive_card_type == BANK_CARD_TYPE.RECHARGE:
            third_ids.append(order.third_id)
    return order_ids, third_ids


@sql_wrapper
def resend_order(order_id):
    order = RechargeOrder.query.filter(RechargeOrder.id == order_id).first()
    if order.status != RECHARGE_ORDER_STATUS.WAIT:
        raise err.DataError('Not Allowed')
    return order


@sql_wrapper
def update_order_inquiry_status(order_id, inquiry_status):
     new_order = RechargeOrder.query.filter(RechargeOrder.id == order_id) \
            .update({'order_inquiry_status': inquiry_status}, synchronize_session='fetch')
     orm.session.commit()

     return new_order


@sql_wrapper
def recharge_getorder_hour(cardcode, hour_ago_date):
    object_order = {}
    order = RechargeOrder.query.filter(
            RechargeOrder.status.in_([RECHARGE_ORDER_STATUS.THIRD, RECHARGE_ORDER_STATUS.WAIT, RECHARGE_ORDER_STATUS.CREATED, RECHARGE_ORDER_STATUS.OVERTIME])
        ).filter(RechargeOrder.created_at <= hour_ago_date).filter(RechargeOrder.receive_card_name == cardcode).filter(RechargeOrder.pay_type is not None).order_by(RechargeOrder.created_at.desc()).first()
    
    if order: 
        object_order = {
            "order_id": order.id if order.id else 0,
            "mch_id": order.mch_id,
            "level": order.star,
            "card_code": order.receive_card_name,
            "pay_type": order.pay_type,
            "created_at": order.created_at
        }
    return object_order


